/**
 * 
 */
package fr.upvm.lem3.vm3d.ui.swing.dataload;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.net.URI;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.hamcrest.core.IsInstanceOf;


import fr.upvm.lem3.vm3d.ui.swing.progressbar.MyProgressBar;

/**
 *******************************************************************
 *Lem3DataLoader.java
 *19.02.2012
 *@author Guy Nougouapi
 *******************************************************************
 *
 *******************************************************************
 */
public class Lem3DataLoader extends JPanel implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3439109576279072816L;

	private static final String BTN_OK_TEXT = "Start";
	private static final String BTN_OK_TOOLTIP_TEXT = "Start loading the data";
	private static final String OPERATION_STARTED = "Operation in progress";
	private static final String OPERATION_DONE = "Done !";
	private static final String BTN_SELECT_TEXT = "Select";
	private static final String FILE_TYPE_LABEL = "Input File Type:";
	private static final String FILE_TYPE_TOOLTIP = "Input file type";
	private static final String FILE_INPUT_PANEL_TITLE = "Input File";
	private static final String DIM_PANEL_TITLE = "Dims";
	private static final String STEP_PANEL_TITLE = "Steps";
	private static final String X_DIM = "X-Dim:";
	private static final String Y_DIM = "Y-Dim:";
	private static final String Z_DIM = "Z-Dim:";
	private static final String X_STEP = "X-Step:";
	private static final String Y_STEP = "Y-Step:";
	private static final String Z_STEP = "Z-Step:";
	private static final String TYPE_UNKNOW = "Not know yet!";
	private static final String CANCEL = "Cancel";
	private static final String CANCEL_TOOLTIP_TEXT = "Cancel the operation";

	private JPanel fileInputPanel;	// 
	private JPanel infoPanel;		// display the statistics (X-,Y-,Z-Dims and X-,Y-,Z-Step) about the input file 
	private JPanel controlPanel;	//display a progressBar 
	
	private JTextField fieldFileInput;
	
	private JLabel labelFileType;
	private JLabel labelXstep;
	private JLabel labelYstep;
	private JLabel labelZstep;
	private JLabel labelXdim;
	private JLabel labelYdim;
	private JLabel labelZdim;
	
	private JButton btnStart;				// click to start with the data loading process
	private JButton btnSelect;				// for the selection of the file to load
	
	private String inputPath;				// input path of the file to import
	private MyProgressBar progressBar;			//custom progressBar object. It is used to display the current state of computing task
	
	private Lem3DataloaderController controller;
	
	public Lem3DataLoader(String name, DataLoadController dataLoaderController){
		super();
		this.setName(name);
		setController(new Lem3DataloaderController(this, dataLoaderController));
		initComponents();
		updateLabelFileType(TYPE_UNKNOW);
		updateDimsStepsLabels(0, 0, 0, 0, 0, 0);
	}

	private void initComponents() {
		this.setLayout(new BorderLayout());
		this.add(getFileInputPanel(), BorderLayout.PAGE_START);
		this.add(getInfoPanel(), BorderLayout.CENTER);
		this.add(getControlPanel(), BorderLayout.PAGE_END);
	}

	/**
	 * @return the controller
	 */
	public Lem3DataloaderController getController() {
		return controller;
	}

	/**
	 * @param controller the controller to set
	 */
	public void setController(Lem3DataloaderController controller) {
		this.controller = controller;
	}

	/**
	 * @return the fileInputPanel
	 */
	public JPanel getFileInputPanel() {
		if( fileInputPanel == null){
			fileInputPanel = new JPanel();
			fileInputPanel.setLayout(new BoxLayout(fileInputPanel, BoxLayout.PAGE_AXIS));
			fileInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, fileInputPanel.getPreferredSize().height));
			/**
			 * create the components to add on this panel
			 */
			JPanel tmpPanel = new JPanel();  //the north panel
			tmpPanel.setLayout(new BoxLayout(tmpPanel, BoxLayout.X_AXIS));
			tmpPanel.setPreferredSize(new Dimension(0, 50));
			tmpPanel.add(Box.createHorizontalGlue());
			tmpPanel.add(Box.createRigidArea(new Dimension(3,0)));
			JTextField textField = getFieldFileInput();
			tmpPanel.add(textField);
			tmpPanel.add(Box.createRigidArea(new Dimension(3,0)));
			getBtnSelect().setPreferredSize(new Dimension(75, 70));
			tmpPanel.add(getBtnSelect());
			tmpPanel.add(Box.createRigidArea(new Dimension(3,0)));
			tmpPanel.setOpaque(true);
		
			//the south panel
			JPanel tmpPanel2 = new JPanel();
			tmpPanel2.setLayout(new FlowLayout(FlowLayout.LEFT));
			tmpPanel2.setPreferredSize(new Dimension(0, 40));
			tmpPanel2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			JLabel label = createLabel(FILE_TYPE_LABEL,FILE_TYPE_TOOLTIP,new Font("Dialog", Font.BOLD, 11));
			tmpPanel2.add(label);
			tmpPanel2.add(getLabelFileType());
			tmpPanel2.setOpaque(true);
			
			//add the component to the underlayed panel
			fileInputPanel.add(tmpPanel);
			fileInputPanel.add(tmpPanel2);
			fileInputPanel.setBorder(BorderFactory.createTitledBorder (
					BorderFactory.createMatteBorder(1, 0, 0, 0, Color.black), FILE_INPUT_PANEL_TITLE, TitledBorder.LEFT,
														TitledBorder.TOP,new Font("Dialog", Font.BOLD, 13)));
			fileInputPanel.setOpaque(true);
			}
		return fileInputPanel;
	}

	/**
	 * @param fileInputPanel the fileInputPanel to set
	 */
	public void setFileInputPanel(JPanel fileInputPanel) {
		this.fileInputPanel = fileInputPanel;
	}

	/**
	 * @return the infoPanel
	 */
	public JPanel getInfoPanel() {
		if(infoPanel == null){
			infoPanel = new JPanel();
			infoPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
			infoPanel.setPreferredSize(new Dimension(0, 50));
			infoPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			infoPanel.add(getDimsPanel());
			infoPanel.add((new JPanel()).add(new JLabel("")));
			infoPanel.add(getStepsPanel());
			infoPanel.setVisible(false);
		}
		return infoPanel;
	}
	
	/*
	 * 
	 */
	private Component getStepsPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		panel.setBorder(BorderFactory.createTitledBorder (
						BorderFactory.createMatteBorder (1, 0, 0, 0, Color.black), STEP_PANEL_TITLE, TitledBorder.LEFT,
															TitledBorder.TOP,new Font("Dialog", Font.BOLD, 13)));
		JPanel panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
		JLabel label = createLabel(X_STEP, null, new Font("Dialog",Font.BOLD,11));
		panelTemp.add(label);
		panelTemp.add(getLabelXstep());
		panel.add(panelTemp);
		panel.add(Box.createRigidArea(new Dimension(0,3)));
		label = createLabel(Y_STEP, null, new Font("Dialog",Font.BOLD,11));
		panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
		panelTemp.add(label);
		panelTemp.add(getLabelYstep());
		panel.add(panelTemp);
		panel.add(Box.createRigidArea(new Dimension(0,3)));
		label = createLabel(Z_STEP, null, new Font("Dialog",Font.BOLD,11));
		panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
		panelTemp.add(label);
		panelTemp.add(getLabelZstep());
		panel.add(panelTemp);
		panel.setOpaque(true);
		return panel;
	}
	/**
	 * 
	 * @return
	 */
	private Component getDimsPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
		panel.setBorder(BorderFactory.createTitledBorder (
						BorderFactory.createMatteBorder(1, 0, 0, 0, Color.black), DIM_PANEL_TITLE, TitledBorder.LEFT,
															TitledBorder.TOP,new Font("Dialog", Font.BOLD, 13)));
		JPanel panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
//		panelTemp.setAlignmentY(Component.LEFT_ALIGNMENT);
		JLabel label = createLabel(X_DIM, null, new Font("Dialog",Font.BOLD,11));
		panelTemp.add(label);
		panelTemp.add(getLabelXdim());
		panel.add(panelTemp);
		panel.add(Box.createRigidArea(new Dimension(0,3)));
		panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
		label = createLabel(Y_DIM, null, new Font("Dialog",Font.BOLD,11));
		panelTemp.add(label);
		panelTemp.add(getLabelYdim());
		panel.add(panelTemp);
		panel.add(Box.createRigidArea(new Dimension(0,3)));
		panelTemp = new JPanel(new FlowLayout());
		panelTemp.setAlignmentX(Component.LEFT_ALIGNMENT);
		label = createLabel(Z_DIM, null, new Font("Dialog",Font.BOLD,11));
		panelTemp.add(label);
		panelTemp.add(getLabelZdim());
		panel.add(panelTemp);
		panel.setOpaque(true);
		return panel;
	}

	/**
	 * @param infoPanel the infoPanel to set
	 */
	public void setInfoPanel(JPanel infoPanel) {
		infoPanel = infoPanel;
	}

	/**
	 * @return the controlPanel
	 */
	public JPanel getControlPanel() {
		if(controlPanel == null){
			controlPanel = new JPanel();
			controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS));
			controlPanel.setPreferredSize(new Dimension(0, 50));
			controlPanel.setBorder(BorderFactory.createEmptyBorder());
			JButton btnStart = getBtnStart();
			btnStart.setPreferredSize(new Dimension(75, 70));
			controlPanel.add(Box.createHorizontalGlue());
			controlPanel.add(Box.createRigidArea(new Dimension(3,0)));
			controlPanel.add((new JPanel()).add(getProgressBar()));
			controlPanel.add(Box.createRigidArea(new Dimension(3,0)));
			controlPanel.add(btnStart);
			controlPanel.add(Box.createRigidArea(new Dimension(3,0)));
			controlPanel.setOpaque(true);
		}
		return controlPanel;
	}

	/**
	 * @param controlPanel the controlPanel to set
	 */
	public void setControlPanel(JPanel controlPanel) {
		this.controlPanel = controlPanel;
	}
	
	/**
	 * create and return  jButton object 
	 * @param text
	 * @param toolTip
	 * @return
	 */
	private  JButton createButton(String text, String toolTip, Insets inset) {
		JButton button = new JButton();
		if(text != null)
			button.setText(text);
		if( toolTip != null)
			button.setToolTipText(toolTip);
		if(inset != null)
			button.setMargin(inset);
		button.setAlignmentX(Component.CENTER_ALIGNMENT);
		button.setAlignmentY(Component.CENTER_ALIGNMENT);
		button.setFocusable(false);
		button.setActionCommand(text);
		return button;
	}

	/**
	 * @return the inputPath
	 */
	public String getInputPath() {
		return inputPath;
	}

	/**
	 * @param inputPath the inputPath to set
	 */
	public void setInputPath(String inputPath) {
		this.inputPath = inputPath;
	}

	/**
	 * @return the progressBar
	 */
	public MyProgressBar getProgressBar() {
		if(progressBar == null){
			//creation of an indeterminate progress bar object. His maxValue ist per default set to 100
			progressBar = new MyProgressBar(OPERATION_STARTED, true); 
			progressBar.setPreferredSize(new Dimension(0, 25));
			progressBar.setMaximumSize(new Dimension(Integer.MAX_VALUE, progressBar.getPreferredSize().height));
			progressBar.addChangeListener(new ChangeListener() {
				public void stateChanged(ChangeEvent e) {
					Object source =e.getSource();
					if(source instanceof JProgressBar){
						if( progressBar.getValue() == progressBar.getMaximum()){
							progressBar.setString(OPERATION_DONE);
							progressBar.setIndeterminate(false);
							getBtnStart().setText(BTN_OK_TEXT);
							getBtnStart().setToolTipText(BTN_OK_TOOLTIP_TEXT);
							getController().getDataLoaderController().getDataLoader().getApplyBtn().setEnabled(true);
							
						}else{
							progressBar.setStringPainted(true);
							getController().getDataLoaderController().getDataLoader().getApplyBtn().setEnabled(false);
						}
					}
				}
			});
		}

		return progressBar;
	}

	/**
	 * @param progressBar the progressBar to set
	 */
	public void setProgressBar(MyProgressBar progressBar) {
		this.progressBar = progressBar;
	}

	/**
	 * @return the labelFileType
	 */
	public JLabel getLabelFileType() {
		if(labelFileType== null){
			labelFileType = new JLabel("File type");
			labelFileType.setToolTipText(FILE_TYPE_TOOLTIP);
		}
		return labelFileType;
	}

	/**
	 * @param labelFileType the labelFileType to set
	 */
	public void setLabelFileType(JLabel labelFileType) {
		this.labelFileType = labelFileType;
	}
	
	/**
	 * 
	 * @param newText
	 */
	public void updateLabelFileType( String newText){
		getLabelFileType().setText(newText);
	}
	
	/**
	 * update those labels with the value given as parameter 
	 * @param xDim
	 * @param yDim
	 * @param zDim
	 * @param xStep
	 * @param yStep
	 * @param zStep
	 */
	public void updateDimsStepsLabels( int xDim, int yDim, int zDim, int xStep, int yStep, int zStep){
		getLabelXdim().setText(Integer.toString(xDim));
		getLabelYdim().setText(Integer.toString(yDim));
		getLabelZdim().setText(Integer.toString(zDim));
		getLabelXstep().setText(Integer.toString(xStep));
		getLabelYstep().setText(Integer.toString(yStep));
		getLabelZstep().setText(Integer.toString(zStep));
	}
	/**
	 * @return the fieldFileInput
	 */
	public JTextField getFieldFileInput() {
		if(fieldFileInput == null){
			fieldFileInput = new JTextField();
			fieldFileInput.setText(getInputPath());
			fieldFileInput.setBackground(Color.white);
			fieldFileInput.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.white, Color.white));
			fieldFileInput.setPreferredSize(new Dimension(0, 25));
			fieldFileInput.setMaximumSize(new Dimension(Integer.MAX_VALUE, fieldFileInput.getPreferredSize().height));
			fieldFileInput.setEditable(true);
			fieldFileInput.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseClicked(MouseEvent e) {
					super.mouseClicked(e);
					if(e.getClickCount() == 2){
						getController().selectFileToLoad(getFieldFileInput().getText().trim());
					}
				}
			});
		}
		return fieldFileInput;
	}

	/**
	 * @param fieldFileInput the fieldFileInput to set
	 */
	public void setFieldFileInput(JTextField fieldFileInput) {
		this.fieldFileInput = fieldFileInput;
	}
	

	/**
	 * @return the labelNbofFileLeft
	 */
	private JLabel createLabel(String text, String toolTip, Font font) {
		JLabel newLabel = new JLabel();
		if(text != null)
			newLabel.setText(text);
		if(toolTip != null)
			newLabel.setToolTipText(toolTip);
		if(font != null)
			newLabel.setFont(font);
			
		return newLabel;
	}

	/**
	 * @return the labelXstep
	 */
	public JLabel getLabelXstep() {
		if(labelXstep == null){
			labelXstep = createLabel(null, null, null);
		}
		return labelXstep;
	}

	/**
	 * @param labelXstep the labelXstep to set
	 */
	public void setLabelXstep(JLabel labelXstep) {
		this.labelXstep = labelXstep;
	}

	/**
	 * @return the labelYstep
	 */
	public JLabel getLabelYstep() {
		if(labelYstep == null){
			labelYstep = createLabel(null, null, null);
		}
		return labelYstep;
	}

	/**
	 * @param labelYstep the labelYstep to set
	 */
	public void setLabelYstep(JLabel labelYstep) {
		this.labelYstep = labelYstep;
	}

	/**
	 * @return the labelZstep
	 */
	public JLabel getLabelZstep() {
		if(labelZstep == null){
			labelZstep = createLabel(null, null, null);
		}
		return labelZstep;
	}

	/**
	 * @param labelZstep the labelZstep to set
	 */
	public void setLabelZstep(JLabel labelZstep) {
		this.labelZstep = labelZstep;
	}

	/**
	 * @return the labelXdim
	 */
	public JLabel getLabelXdim() {
		if(labelXdim == null){
			labelXdim = createLabel(null, null, null);
		}
		return labelXdim;
	}

	/**
	 * @param labelXdim the labelXdim to set
	 */
	public void setLabelXdim(JLabel labelXdim) {
		this.labelXdim = labelXdim;
	}

	/**
	 * @return the labelYdim
	 */
	public JLabel getLabelYdim() {
		if(labelYdim == null){
			labelYdim = createLabel(null, null, null);
		}
		return labelYdim;
	}

	/**
	 * @param labelYdim the labelYdim to set
	 */
	public void setLabelYdim(JLabel labelYdim) {
		this.labelYdim = labelYdim;
	}

	/**
	 * @return the labelZdim
	 */
	public JLabel getLabelZdim() {
		if(labelZdim == null){
			labelZdim = createLabel(null, null, null);
		}
		return labelZdim;
	}

	/**
	 * @param labelZdim the labelZdim to set
	 */
	public void setLabelZdim(JLabel labelZdim) {
		this.labelZdim = labelZdim;
	}

	/**
	 * @return the btnStart
	 */
	public JButton getBtnStart() {
		if( btnStart == null){
			btnStart = createButton(BTN_OK_TEXT,BTN_OK_TOOLTIP_TEXT,null);
			btnStart.addActionListener(new MyButtonListener());
			btnStart.setEnabled(false);
		}
		return btnStart;
	}

	/**
	 * @param btnStart the btnStart to set
	 */
	public void setBtnStart(JButton btnStart) {
		this.btnStart = btnStart;
	}

	/**
	 * @return the btnSelect
	 */
	public JButton getBtnSelect() {
		if( btnSelect == null){
			btnSelect = createButton(BTN_SELECT_TEXT,null,null);
			btnSelect.addActionListener(new MyButtonListener());
		}
		return btnSelect;
	}

	/**
	 * @param btnSelect the btnSelect to set
	 */
	public void setBtnSelect(JButton btnSelect) {
		this.btnSelect = btnSelect;
	}
	
	/**
	 * Listner event on the button with has register
	 *******************************************************************
	 *Lem3DataLoader.java
	 *21.02.2012
	 *@author Guy Nougouapi
	 *******************************************************************
	 *
	 *******************************************************************
	 */
	class MyButtonListener implements ActionListener{
		
		Thread thread=null;
		@Override
		public void actionPerformed(ActionEvent e) {
			String cmd = e.getActionCommand();
			JButton btn = (JButton)e.getSource();
			Dimension oldDimension = btn.getPreferredSize();
			switch (cmd) {
			case BTN_SELECT_TEXT:
				getController().selectFileToLoad(getFieldFileInput().getText().trim());
				break;
			case BTN_OK_TEXT:
				if(btn.getText().equals(BTN_OK_TEXT)){
					//Actions to execute
					thread =new Thread( 
								(new Runnable() {
								@Override
								public void run() {
									synchronized(this.getClass()){
										System.out.println("The thread has been launched");
										getProgressBar().setValue(0);
										getProgressBar().setString(OPERATION_STARTED);
										getProgressBar().updateValue(0, OPERATION_STARTED);
										getController().startReadFileFromDisk(getInputPath());
										//notify the user that the operation has finished by update the value of  the progress bar to it max 
										if(!thread.interrupted())
												getProgressBar().setValue(100);
										}
									}
							})
					);
					thread.setName("Lem3Loader");
					thread.start();
					//turn it text label into "Cancel"
					btn.setText(CANCEL);
					btn.setToolTipText(CANCEL_TOOLTIP_TEXT);

					}else{//the user want to break the operation
						System.out.println("Cancel button");
						// Kill the running thread with the name "Lem3Loader"
						//stop the timer for the progressbar
						Thread[] threads = new Thread[Thread.activeCount()];
						Thread.enumerate(threads);
						for(Thread ct: threads){
							if(ct.getName().equals("Lem3Loader"))
								ct.interrupt();
							System.out.print(ct.getName()+"\thas been interupted");
						}
						btn.setText(BTN_OK_TEXT);
						btn.setToolTipText(BTN_OK_TOOLTIP_TEXT);
						getProgressBar().setValue(0);
						getProgressBar().setIndeterminate(false);
						getProgressBar().setStringPainted(false);
					}
				break;
			default:
				break;
			}
			
		}
		
	}
}
